SFINAE out duration converting constructor if the constructor would otherwise cause a ratio compile-time overflow. This fixes LWG 2094. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@189722 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/chrono b/include/chrono index 9fb7743..afc5181 100644 --- a/include/chrono +++ b/include/chrono
@@ -409,6 +409,37 @@ static_assert(!__is_duration<_Rep>::value, "A duration representation can not be a duration"); static_assert(__is_ratio<_Period>::value, "Second template parameter of duration must be a std::ratio"); static_assert(_Period::num > 0, "duration period must be positive"); + + template <class _R1, class _R2> + struct __no_overflow + { + private: + static const intmax_t __gcd_n1_n2 = __static_gcd<_R1::num, _R2::num>::value; + static const intmax_t __gcd_d1_d2 = __static_gcd<_R1::den, _R2::den>::value; + static const intmax_t __n1 = _R1::num / __gcd_n1_n2; + static const intmax_t __d1 = _R1::den / __gcd_d1_d2; + static const intmax_t __n2 = _R2::num / __gcd_n1_n2; + static const intmax_t __d2 = _R2::den / __gcd_d1_d2; + static const intmax_t max = -((intmax_t(1) << (sizeof(intmax_t) * CHAR_BIT - 1)) + 1); + + template <intmax_t _Xp, intmax_t _Yp, bool __overflow> + struct __mul // __overflow == false + { + static const intmax_t value = _Xp * _Yp; + }; + + template <intmax_t _Xp, intmax_t _Yp> + struct __mul<_Xp, _Yp, true> + { + static const intmax_t value = 1; + }; + + public: + static const bool value = (__n1 <= max / __d2) && (__n2 <= max / __d1); + typedef ratio<__mul<__n1, __d2, !value>::value, + __mul<__n2, __d1, !value>::value> type; + }; + public: typedef _Rep rep; typedef _Period period; @@ -440,9 +471,10 @@ duration(const duration<_Rep2, _Period2>& __d, typename enable_if < + __no_overflow<_Period2, period>::value && ( treat_as_floating_point<rep>::value || - (ratio_divide<_Period2, period>::type::den == 1 && - !treat_as_floating_point<_Rep2>::value) + (__no_overflow<_Period2, period>::type::den == 1 && + !treat_as_floating_point<_Rep2>::value)) >::type* = 0) : __rep_(_VSTD::chrono::duration_cast<duration>(__d).count()) {}